package org.lvgo.singleton.lazy;

/**
 * 这种方式采用双锁机制，安全且在多线程情况下能保持高性能。
 * getInstance() 的性能对应用程序很关键。
 * <p>
 * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 * <p>
 * Broken under Java 1.4
 *
 * @author lvgo
 * @version 1.0
 * @Description: 双重锁单例模式
 * @date 18-8-22 下午1:57
 */
public class DoubleCheckLockingSingleton {

    private volatile static DoubleCheckLockingSingleton doubleCheckLockingSingleton;

    /**
     * 私有化构造器
     */
    private DoubleCheckLockingSingleton() {
        // 解决反射创建对象破解单例模式
        if (doubleCheckLockingSingleton != null) {
            throw new IllegalStateException("Already initialized");
        }
    }

    public static DoubleCheckLockingSingleton getInstance() {

        // 定义这个局部变量可以提高大约25%的性能 依据:Joshua Bloch "Effective Java, Second Edition", p. 283-284
        DoubleCheckLockingSingleton current = doubleCheckLockingSingleton;
        // 检查当前对象是否实例化
        if (current == null) {
            // 此时为了保证线程安全,我们不清楚其他线程是否已经实例化该对象,所以将类上锁达到互斥效果
            synchronized (DoubleCheckLockingSingleton.class) {
                /*
                 * 再次将实例分配给局部变量并检查它是否由其他某个线程初始化
                 * 当前线程被阻止进入锁定区域。 如果它已初始化，那么我们可以
                 * 返回先前创建的实例，就像上面检查对象是否为空一样。
                 */
                current = doubleCheckLockingSingleton;
                if (current == null) {
                    // 如果此时该类还没有被实例化,那么我们就可以安全的实例化一个单例的该对象实例.
                    doubleCheckLockingSingleton = current = new DoubleCheckLockingSingleton();
                }
            }
        }
        return current;
    }

    /**
     * 解决反序列化创建对象破坏单例模式
     */
    private Object readResolve() {
        return doubleCheckLockingSingleton;
    }
}
